# -*- coding:utf-8 -*-
__author__ = 'Dragon Sun'
__date__ = '2025-06-21 22:23:05'

from pathlib import Path
from typing import Optional

from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QWidget, QLabel
from apscheduler.schedulers.background import BackgroundScheduler
from dsOKXv5.data_types import 交易方向枚举
from dsOKXv5.models.m_持仓 import 持仓模型类
from dsOKXv5.utils.交易 import 计算未实现收益额, 计算未实现收益率, 计算合约手续费
from dsPyLib.utils.日期时间 import 获取时长字符串
from dsPySide6.utils.func import load_ui


class 持仓视图控制器类(QObject):
    默认宽度 = 860
    默认高度 = 87

    _信号_更新持仓时长显示 = Signal()  # 内部使用，计时器更新界面

    # noinspection PyUnresolvedReferences
    def __init__(self, 调度器: BackgroundScheduler):
        super().__init__()

        # 视图
        视图文件名 = Path(__file__).resolve().parent / '持仓视图.ui'
        self.视图 = load_ui(ui_file=视图文件名, custom_widgets=[], parent=None)

        # 样式常量
        self._红色样式 = 'color: rgb(202, 63, 100);'
        self._绿色样式 = 'color: rgb(37, 167, 80);'
        self._红色边框样式 = '#PositionWidget { border: 3px solid rgb(202, 63, 100); }'
        self._绿色边框样式 = '#PositionWidget { border: 3px solid rgb(37, 167, 80); }'
        self._灰色边框样式 = '#PositionWidget { border: 3px solid grey; }'

        # 组件映射
        self._持仓窗体: QWidget = self.视图
        self._无持仓标签: QLabel = self.视图.lblNoPos
        self._持仓容器: QWidget = self.视图.ChiCangWidget
        self._标的标签: QLabel = self.视图.lblInstID
        self._持仓方向标签: QLabel = self.视图.lblPosSide
        self._订单类型标签: QLabel = self.视图.lblOrderType
        self._杠杆倍数标签: QLabel = self.视图.lblLeverage
        self._保证金模式标签: QLabel = self.视图.lblMgnMode
        self._净收益标签: QLabel = self.视图.lblProfit
        self._净收益后缀标签: QLabel = self.视图.lblProfitSuffix
        self._净收益率标签: QLabel = self.视图.lblProfitRatio
        self._净收益率后缀标签: QLabel = self.视图.lblProfitRatioSuffix
        self._浮动收益标签: QLabel = self.视图.lblFloatingProfit
        self._浮动收益后缀标签: QLabel = self.视图.lblFloatingProfitSuffix
        self._浮动收益率标签: QLabel = self.视图.lblFloatingProfitRatio
        self._浮动收益率后缀标签: QLabel = self.视图.lblFloatingProfitRatioSuffix
        self._标记价格标签: QLabel = self.视图.lblMarkedPrice
        self._持仓量标签: QLabel = self.视图.lblPos
        self._开仓均价标签: QLabel = self.视图.lblPx
        self._开仓时间标签: QLabel = self.视图.lblOpenTime
        self._持仓时长标签: QLabel = self.视图.lblPosDuration
        self._保证金标签: QLabel = self.视图.lblMargin
        self._止盈触发价标签: QLabel = self.视图.lblTakeProfit
        self._止损触发价标签: QLabel = self.视图.lblStopLoss

        # 变量
        self._持仓: Optional[持仓模型类] = None

        # 组件初始化设置
        self._无持仓标签.setStyleSheet('')
        self.传递持仓(持仓=self._持仓)

        # 调度器
        self._调度器: BackgroundScheduler = 调度器
        self._调度器.add_job(func=self._调度器任务处理, trigger='cron', second='*')

        # 绑定信号
        self._信号_更新持仓时长显示.connect(self._更新持仓时长显示)

    def 传递持仓(self, 持仓: Optional[持仓模型类]):
        self._持仓 = 持仓

        # 根据持仓决定显示：无持仓 还是 持仓内容
        self._无持仓标签.setVisible(持仓 is None)
        self._持仓容器.setVisible(持仓 is not None)

        if 持仓 is None:
            self._持仓窗体.setStyleSheet(self._灰色边框样式)
            return

        # ---------- 下面是不会随着标记价格变化的项 ---------- #

        # 窗体
        self._持仓窗体.setStyleSheet(self._红色边框样式 if self._持仓.方向 == 交易方向枚举.多 else self._绿色边框样式)

        # 标的
        self._标的标签.setText(self._持仓.标的)

        # 持仓方向
        self._持仓方向标签.setText(f'开{self._持仓.方向.name}')
        self._持仓方向标签.setStyleSheet(self._红色样式 if self._持仓.方向 == 交易方向枚举.多 else self._绿色样式)

        # 订单类型
        self._订单类型标签.setText(f'{self._持仓.订单类型.name}')

        # 杠杆倍数
        self._杠杆倍数标签.setText(f'{self._持仓.杠杆:.2f}x')

        # 保证金模式
        self._保证金模式标签.setText(self._持仓.保证金模式.name)

        # 持仓量
        self._持仓量标签.setText(f'{self._持仓.持仓量:.2f}')

        # 开仓均价
        开仓均价标签提示 = (
                f'盈亏平衡价: {self._持仓.盈亏平衡价:.2f}'
                + f'\n预估强评价: {self._持仓.预估强平价:.2f}'
        )
        self._开仓均价标签.setText(f'{self._持仓.开仓均价:.2f}')
        self._开仓均价标签.setToolTip(开仓均价标签提示)

        # 开仓时间
        开仓时间 = self._持仓.开仓时间.strftime('%Y-%m-%d %H:%M:%S')
        self._开仓时间标签.setText(开仓时间)

        # 持仓时间
        self._更新持仓时长显示()

        # 保证金
        保证金标签提示 = f'维持保证金率: {self._持仓.维持保证金率 * 100:.2f}%'
        self._保证金标签.setText(f'{self._持仓.保证金:.2f}')
        self._保证金标签.setToolTip(保证金标签提示)

        # 止盈止损初始显示
        self._止盈触发价标签.setText('---')
        self._止盈触发价标签.setToolTip('')
        self._止盈触发价标签.setStyleSheet(self._红色样式)
        self._止损触发价标签.setText('---')
        self._止损触发价标签.setToolTip('')
        self._止损触发价标签.setStyleSheet(self._绿色样式)

        # 标记价格(顺带更新其它内容)
        self.传递标记价格(标记价格=self._持仓.标记价格)

    def 传递标记价格(self, 标记价格: float):
        if self._持仓 is None:
            return

        self._持仓.标记价格 = 标记价格

        # ---------- 下面是会随着标记价格变化的项 ---------- #

        # 手续费
        开仓手续费 = abs(self._持仓.开仓手续费)
        预估平仓手续费 = 计算合约手续费(成交张数=self._持仓.持仓量, 成交均价=self._持仓.标记价格)
        预估总手续费 = 开仓手续费 + 预估平仓手续费

        # 浮动收益额/浮动收益率
        浮动收益额 = 计算未实现收益额(
            持仓张数=self._持仓.持仓量, 开仓均价=self._持仓.开仓均价, 价格=self._持仓.标记价格, 交易方向=self._持仓.方向)
        浮动收益率 = 计算未实现收益率(收益额=浮动收益额, 保证金=self._持仓.保证金)

        # 净收益/净收益率
        净收益额 = 浮动收益额 - 预估总手续费
        净收益率 = 净收益额 / self._持仓.保证金

        # 提示
        标签提示 = (
                f'开仓手续费: {开仓手续费:.2f}'
                + f'\n预估平仓手续费: {预估平仓手续费:.2f}'
                + f'\n预估总手续费: {预估总手续费:.2f}'
        )

        # 颜色
        净收益颜色样式 = self._红色样式 if 净收益额 >= 0 else self._绿色样式
        浮动收益颜色样式 = self._红色样式 if 浮动收益额 >= 0 else self._绿色样式

        # 设置净收益组件显示
        self._净收益标签.setText(f'{净收益额:.2f}')
        self._净收益标签.setStyleSheet(净收益颜色样式)
        self._净收益标签.setToolTip(标签提示)
        self._净收益率标签.setText(f'{净收益率 * 100:.2f}')
        self._净收益率标签.setStyleSheet(净收益颜色样式)
        self._净收益率标签.setToolTip(标签提示)
        self._净收益后缀标签.setStyleSheet(净收益颜色样式)
        self._净收益率后缀标签.setStyleSheet(净收益颜色样式)

        # 设置浮动收益组件显示
        self._浮动收益标签.setText(f'{浮动收益额:.2f}')
        self._浮动收益标签.setStyleSheet(浮动收益颜色样式)
        self._浮动收益标签.setToolTip(标签提示)
        self._浮动收益率标签.setText(f'{浮动收益率 * 100:.2f}')
        self._浮动收益率标签.setStyleSheet(浮动收益颜色样式)
        self._浮动收益率标签.setToolTip(标签提示)
        self._浮动收益后缀标签.setStyleSheet(浮动收益颜色样式)
        self._浮动收益率后缀标签.setStyleSheet(浮动收益颜色样式)

        # 标记价格
        self._标记价格标签.setText(f'{self._持仓.标记价格:.2f}')

        # 止盈止损
        if self._持仓.止盈止损单 is None:
            return

        if self._持仓.止盈止损单.止盈触发价 != -1:
            止盈未实现收益额 = 计算未实现收益额(
                持仓张数=self._持仓.持仓量, 开仓均价=self._持仓.开仓均价, 价格=self._持仓.止盈止损单.止盈触发价, 交易方向=self._持仓.方向)
            止盈未实现收益率 = 止盈未实现收益额 / self._持仓.保证金

            止盈平仓手续费 = 计算合约手续费(成交张数=self._持仓.持仓量, 成交均价=self._持仓.止盈止损单.止盈触发价)
            止盈总手续费 = self._持仓.开仓手续费 + 止盈平仓手续费

            止盈净收益额 = 止盈未实现收益额 - 止盈总手续费
            止盈净收益率 = 止盈净收益额 / self._持仓.保证金

            止盈标签提示 = (
                    f'净收益额: {止盈净收益额:.2f}'
                    + f'\n净收益率: {止盈净收益率 * 100:.2f}%'
                    + '\n'
                    + f'\n未实现收益额: {止盈未实现收益额:.2f}'
                    + f'\n未实现收益率: {止盈未实现收益率 * 100:.2f}%'
                    + '\n'
                    + f'\n平仓手续费: {止盈平仓手续费:.2f}'
                    + f'\n总手续费: {止盈总手续费:.2f}'
            )
            self._止盈触发价标签.setText(f'{self._持仓.止盈止损单.止盈触发价}')
            self._止盈触发价标签.setStyleSheet(self._红色样式)
            self._止盈触发价标签.setToolTip(止盈标签提示)

        if self._持仓.止盈止损单.止损触发价 != -1:
            止损未实现收益额 = 计算未实现收益额(
                持仓张数=self._持仓.持仓量, 开仓均价=self._持仓.开仓均价, 价格=self._持仓.止盈止损单.止损触发价, 交易方向=self._持仓.方向)
            止损未实现收益率 = 止损未实现收益额 / self._持仓.保证金

            止损平仓手续费 = 计算合约手续费(成交张数=self._持仓.持仓量, 成交均价=self._持仓.止盈止损单.止损触发价)
            止损总手续费 = abs(self._持仓.开仓手续费) + 止损平仓手续费

            止损净收益额 = 止损未实现收益额 - 止损总手续费
            止损净收益率 = 止损净收益额 / self._持仓.保证金

            止损标签提示 = (
                    f'净收益额: {止损净收益额:.2f}'
                    + f'\n净收益率: {止损净收益率 * 100:.2f}%'
                    + '\n'
                    + f'\n未实现收益额: {止损未实现收益额:.2f}'
                    + f'\n未实现收益率: {止损未实现收益率 * 100:.2f}%'
                    + '\n'
                    + f'\n平仓手续费: {止损平仓手续费:.2f}'
                    + f'\n总手续费: {止损总手续费:.2f}'
            )
            self._止损触发价标签.setText(f'{self._持仓.止盈止损单.止损触发价}')
            self._止损触发价标签.setStyleSheet(self._绿色样式)
            self._止损触发价标签.setToolTip(止损标签提示)

    def _更新持仓时长显示(self):
        if self._持仓 is None:
            return

        时长字符串 = 获取时长字符串(开始时间=self._持仓.开仓时间)
        self._持仓时长标签.setText(时长字符串)

    def _调度器任务处理(self):
        self._信号_更新持仓时长显示.emit()  # 为了避免在线程中更新UI界面，采用信号处理
